package yana.tpe.onlineshop.domain.dao.impl;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.type.IntegerType;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.stereotype.Repository;
import yana.tpe.onlineshop.domain.dao.CategoryDao;
import yana.tpe.onlineshop.domain.domains.Category;

/**
 *
 */
@Repository
public class CategoryDaoImpl extends AbstracDaoImpl<Integer, Category>
        implements CategoryDao {

    @Override
    protected Class<Category> getDomainClass() {
        return Category.class;
    }

    @Override
    public void move(Integer newParentId, Integer categoryId) {
        hibernateTemplate.bulkUpdate(
                "update category set category.parent = ? "
                + "where category.id = ?", newParentId, categoryId);
        flush();
    }

    @Override
    public void delete(Integer categoryId) {
        delete(get(categoryId));
        flush();
    }

    @Override
    public List<Category> getCategoryWithParents(Integer categoryId) {
        List<Category> list = new ArrayList<Category>();
        Category previous;
        
        while((previous = get(categoryId)) != null){
            previous.setChilds(Collections.<Category>emptySet());
            list.add(previous);
            categoryId = previous.getParent() != null ? previous.getParent().getId() : null;
        }

        if (!list.isEmpty()) {
            list.add(new Category("Home", null));
        }
        
        Collections.reverse(list);

        flush();
        return list;
    }

    @Override
    public List<Category> getChildCategoris(final Integer parentId) {

        List<Category> list;
        if (parentId == null) {
            list = hibernateTemplate.find("FROM category WHERE id NOT IN ("
                    + "SELECT DISTINCT child.id FROM category node, IN(node.childs) child)");
        } else {
            list = hibernateTemplate.executeWithNativeSession(
                    new HibernateCallback<List<Category>>() {

                @Override
                public List<Category> doInHibernate(Session session)
                        throws HibernateException, SQLException {
                    Query query = session.createQuery(
                            "from category where parent = :parent");
                    query.setParameter("parent", parentId, new IntegerType());
                    return query.list();
                }
            });
        }

        flush();
        return list;
    }

    @Override
    public List<Category> getCategoryForEdit() {
        List<Category> list = list();
        List<Category> root = new ArrayList<Category>();
        for (Category category : list) {
            if (category.getParent() == null) {
                completeChilds(category);
                root.add(category);
            }
        }
        flush();
        return root;
    }

    @Override
    public Category getCategoryParent(Integer categoryId) {
        Category get = get(categoryId);
        if (get != null) {
            return get.getParent();
        } else {
            return null;
        }
    }

    private void completeChilds(Category c) {
        Set<Category> childs = new HashSet<Category>();
        for (Category child : c.getChilds()) {
            completeChilds(child);
            childs.add(child);
        }
        c.setChilds(childs);
    }
}
